package xyz.lwm.lazycat.banner;

import xyz.lwm.lazycat.setting.Setting;
import xyz.lwm.lazycat.utility.IoUtil;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.exception.LazycatException;
import xyz.lwm.lazycat.utility.resource.Location;
import xyz.lwm.lazycat.utility.resource.Resource;
import xyz.lwm.lazycat.utility.scan.ScanUtil;

import java.io.IOException;
import java.util.Comparator;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * banner
 *
 * @author lwm
 */
public final class Banner {

    // variables regex in banner text
    private static final Pattern VARIABLE_REGEX = Pattern.compile("\\$\\{\\s*([^}^\\s]+)\\s*}");

    // banner location (classpath:banner.txt)
    private final String bannerLocation;

    public Banner(String bannerLocation) {
        this.bannerLocation = bannerLocation;
    }

    public Banner(String bannerPath, Location location) {
        this(location.toPattern(bannerPath));
    }

    /**
     * Print banner
     *
     * @param out consumer for banner text
     */
    public void print(Consumer<String> out) {
        ScanUtil.scanResources(bannerLocation).stream()
                .sorted(Comparator.comparing(Resource::getName))
                .filter(r -> r.exists() && !r.isDir()).findFirst()
                .ifPresent(r -> {
                    try {
                        It.of(r.getInputStream())
                                .let(IoUtil::readUtf8)
                                .let(this::analyze).also(out);
                    } catch (IOException e) {
                        throw new LazycatException(e);
                    }
                });
    }

    /**
     * analyze banner text and replace variables
     *
     * @param bannerText banner text
     * @return analyzed banner text
     */
    private String analyze(String bannerText) {
        // banner builder
        StringBuilder bannerBuilder = new StringBuilder();

        // environment
        Setting setting = Setting.get();
        // match variable and split banner text
        Matcher matcher = VARIABLE_REGEX.matcher(bannerText);
        int start = 0;
        while (matcher.find()) {
            int pos = matcher.start();
            bannerBuilder.append(bannerText, start, pos);
            // get variable value
            String value = setting.get(matcher.group(1)).getOr(matcher.group());
            bannerBuilder.append(value);
            start = matcher.end();
        }
        bannerBuilder.append(bannerText, start, bannerText.length());

        return bannerBuilder.toString();
    }

}
